/*Author: Rony Lahav (ID:043489889)*/

import java.util.HashMap;

/**
 * This class processes a single received UDP message
 */
public class UDPListenerProcessMessage implements Runnable{
	
	protected String senderIP;
	protected int senderPort;
	protected String senderID;
	protected String msg;
	protected HashMap<String,String> parsedMsg;
	protected long uniqueID;
	
	public UDPListenerProcessMessage(String senderIP, int senderPort, String msg){
		this.senderIP=senderIP;
		this.senderPort=senderPort;
		this.msg=msg;
	}
	
	public void run(){
		boolean ignore=false;
		boolean fromMyMainSN=false;
		if (!final_project.isShutDown()){
			parsedMsg=MessageCenter.getInstance().parseValidMessage(msg, senderID, senderIP);
			DBTuple senderTuple = DataBase.getInstance().findTuple(senderIP+":"+senderPort);
			if (senderTuple == null)	//it's in snList
				senderTuple = DataBase.getInstance().findSN(senderIP+":"+senderPort);
			if (senderTuple == null)	//it's my main SN
				senderTuple = final_project.getMyMainSN();
			if (final_project.getMyMainSN()!=null && senderTuple.getKey().equals(final_project.getMyMainSN().getKey()))
				fromMyMainSN=true;
			if (!final_project.inFallBackMode){	//i'm a regular peer => who sent the message?
				//if the message isn't from my main SN it means i got a message from a peer => ignore
				if (final_project.getMyMainSN()!=null && !senderTuple.getKey().equals(final_project.getMyMainSN().getKey()))
					if (!final_project.inFallBackMode){	//got irrelevant message from a peer (still in SN mode) => ignore
						ignore=true;
					}
			}
			if (!ignore){
				//update last connection time of a peer and set its status to online
				senderTuple.setLastConnectionTime(System.currentTimeMillis());
				senderTuple.setStatus("1");
				senderID=parsedMsg.get(MessageCenter.VAR_ID);
				//update ID of peer if it's the first time we get a message from it
				if (senderTuple.getPeerID()==null)
					senderTuple.setPeerID(senderID);
				String msgType=parsedMsg.get("TYPE");
				DataBase.getInstance().updateTuple(senderTuple);
				//check only for IM and FT because AV was already handled and GET is received in TCP thread
				if (!final_project.isShutDown()){
					if (msgType.equals(MessageCenter.TYPE_IM)){
						//an IM will never be sent to a regular peer by an SN he's not yet connected to, or from a peer that isn't in FallBack mode
						//so if this is the message it means a peer in FallBack sent it and i can go to FallBack as well
						if (!senderTuple.IsMainSN()){
							final_project.goToFallBackMode();
							DataBase.getInstance().updateTuple(senderTuple);
							IMManager.getInstance().sendIMToPeers(parsedMsg.get(MessageCenter.VAR_MSG), senderID);
						}
					}
					else if (msgType.equals(MessageCenter.TYPE_FT)){
						//an FT will never be sent to a regular peer by an SN he's not yet connected to, or from a peer that isn't in FallBack mode
						//so if this is the message it means a peer in FallBack sent it and i can go to FallBack as well
						if (!senderTuple.IsMainSN()){
							final_project.goToFallBackMode();
							DataBase.getInstance().updateTuple(senderTuple);
							long id = final_project.getNewUniqueID();
							//activate an outgoing TCP session for sending a GET message and receiving a file 
							SingleTCPOutgoingConnection tcpOutCon = new SingleTCPOutgoingConnection(senderIP, Integer.parseInt(parsedMsg.get(MessageCenter.VAR_TCP)), parsedMsg.get(MessageCenter.VAR_FILE), Integer.parseInt(parsedMsg.get(MessageCenter.VAR_SIZE)), id);
							Thread thread = new Thread(tcpOutCon);
							final_project.addThreadToLivingList(id, thread);
							thread.start();
						}
					}
					else if (msgType.equals(MessageCenter.TYPE_AV)){
						if(fromMyMainSN)
							DataBase.getInstance().updateMainSN(senderTuple);
					}
					else if (msgType.equals(MessageCenter.TYPE_SNLIST)){
						//data already in DB from parseMessage function
						senderTuple.setIsMainSN(true);
						senderTuple.setIsSN(true);
						DataBase.getInstance().updateMainSN(senderTuple);
						DataBase.getInstance().updateSN(senderTuple);
						DataBase.getInstance().updateExistingTuple(senderTuple);
					}
				}
			}
		}
	}

}
